import io
from io import BytesIO

import aiofiles
import os
import uuid
from PIL import Image
from pathlib import Path

from loguru import logger
from fastapi import status
from sqlalchemy.orm import Session

from labelu.internal.common.config import settings
from labelu.internal.common.error_code import ErrorCode
from labelu.internal.common.error_code import LabelUException
from labelu.internal.domain.models.user import User
from labelu.internal.domain.models.task import TaskStatus
from labelu.internal.domain.models.attachment import TaskAttachment
from labelu.internal.adapter.persistence import crud_task
from labelu.internal.adapter.persistence import crud_attachment
from labelu.internal.application.command.attachment import AttachmentCommand
from labelu.internal.application.command.attachment import AttachmentDeleteCommand
from labelu.internal.application.response.base import CommonDataResp
from labelu.internal.application.response.attachment import AttachmentResponse

from minio import Minio
from minio.error import S3Error

# 原始文件备份---------------------------

# 创建 MinIO 客户端实例
minio_client = Minio(
    "192.168.9.225:9000",
    access_key="admin",
    secret_key="Flzx3qc@2022!",
    secure=False
)


async def create(db: Session, task_id: int, cmd: AttachmentCommand, current_user: User) -> AttachmentResponse:
    task = crud_task.get(db=db, task_id=task_id)
    if not task:
        logger.error("cannot find task: {}", task_id)
        raise LabelUException(
            code=ErrorCode.CODE_50002_TASK_NOT_FOUND,
            status_code=status.HTTP_404_NOT_FOUND,
        )

    try:
        # 文件的相对路径
        path_filename = cmd.file.filename.split("/")
        filename = str(uuid.uuid4())[0:8] + "-" + path_filename[-1]

        # 读取文件内容
        content = await cmd.file.read()  # 确保这里调用了 read() 方法

        # 在MinIO中创建bucket（如果尚不存在）
        bucket_name = "data"
        if not minio_client.bucket_exists(bucket_name):
            minio_client.make_bucket(bucket_name)

        # 上传文件到MinIO
        minio_client.put_object(
            bucket_name, filename, io.BytesIO(content), length=len(content), part_size=10*1024*1024
        )

        # 如果文件是图片，创建缩略图
        if cmd.file.content_type.startswith("image/"):
            image = Image.open(io.BytesIO(content))
            image.thumbnail(
                (
                    round(image.width / image.height * settings.THUMBNAIL_HEIGH_PIXEL),
                    settings.THUMBNAIL_HEIGH_PIXEL,
                ),
            )
            if image.mode != "RGB":
                image = image.convert("RGB")
            thumbnail_filename = f"{filename[:-len(Path(filename).suffix)]}-thumbnail{Path(filename).suffix}"
            image_byte_array = io.BytesIO()
            image.save(image_byte_array, format='JPEG')
            image_byte_array.seek(0)  # 将指针移到开头
            minio_client.put_object(
                bucket_name, thumbnail_filename, image_byte_array, length=len(image_byte_array.getvalue()), part_size=10*1024*1024
            )
    except S3Error as e:
        logger.error(e)
        raise LabelUException(
            code=ErrorCode.CODE_51000_CREATE_ATTACHMENT_ERROR,
            status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
        )

    attachment_url_path = f"{settings.MINIO_URL}/{bucket_name}/{filename}"
    # 增加任务文件记录
    with db.begin():
        attachment = crud_attachment.create(
            db=db,
            attachment=TaskAttachment(
                path=filename,
                url=attachment_url_path,
                filename=filename,
                created_by=current_user.id,
                updated_by=current_user.id,
                task_id=task_id,
            ),
        )

    # 返回响应
    return AttachmentResponse(
        id=attachment.id,
        url=attachment_url_path,
        filename=filename,
    )


async def download_attachment(file_path: str) -> str:

    # check file exist
    file_full_path = settings.MEDIA_ROOT.joinpath(file_path.lstrip("/"))
    if not file_full_path.is_file() or not file_full_path.exists():
        logger.error("attachment not found:{}", file_full_path)
        raise LabelUException(
            code=ErrorCode.CODE_51001_TASK_ATTACHMENT_NOT_FOUND,
            status_code=status.HTTP_404_NOT_FOUND,
        )

    # response
    return file_full_path


async def delete(
    db: Session, task_id: int, cmd: AttachmentDeleteCommand, current_user: User
) -> CommonDataResp:

    # get task
    task = crud_task.get(db=db, task_id=task_id)
    if not task:
        logger.error("cannot find task:{}", task_id)
        raise LabelUException(
            code=ErrorCode.CODE_51001_TASK_ATTACHMENT_NOT_FOUND,
            status_code=status.HTTP_404_NOT_FOUND,
        )

    if task.created_by != current_user.id:
        logger.error(
            "cannot delete attachment, the task owner is:{}, the delete operator is:{}",
            task.created_by,
            current_user.id,
        )
        raise LabelUException(
            code=ErrorCode.CODE_30001_NO_PERMISSION,
            status_code=status.HTTP_403_FORBIDDEN,
        )

    # delete media
    try:
        attachments = crud_attachment.get_by_ids(
            db=db, attachment_ids=cmd.attachment_ids
        )
        for attachment in attachments:
            file_full_path = Path(settings.MEDIA_ROOT).joinpath(attachment.path)
            os.remove(file_full_path)
    except Exception as e:
        logger.error(e)

    # delete
    with db.begin():
        crud_attachment.delete(db=db, attachment_ids=cmd.attachment_ids)

    # response
    return CommonDataResp(ok=True)
